home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / umich / network / ka9q / nhclb120.zoo / eagle.c < prev    next >
C/C++ Source or Header  |  1992-02-11  |  24KB  |  805 lines

  1. /*
  2.  * Interface driver for the EAGLE board for KA9Q's TCP/IP on an IBM-PC ONLY!
  3.  *
  4.  *  Written by Art Goldman, WA3CVG - (c) Copyright 1987 All Rights Reserved
  5.  *  Permission for non-commercial use is hereby granted provided this notice
  6.  *  is retained.  For info call: (301) 997-3838.
  7.  *
  8.  *  10 Jan 88    ng6q    - Corrected IDLE comparison in doegstat.
  9.  *   6 Apr 88    ng6q    - Changed eg_raw to prevent calling egtxint with a
  10.  *              packet in sndbuf.  Initialized sndq and rcvq in
  11.  *              eg_attach.  Added carrier detect check before
  12.  *              slot time delay in egtxint.  Should make major
  13.  *              changes to egtxint to avoid delay loops while
  14.  *              masked for receive interrupts.
  15.  */
  16.  
  17. #include <stdio.h>
  18. #include "global.h"
  19. #include "mbuf.h"
  20. #include "iface.h"
  21. #include "eagle.h"
  22. #include "8530.h"
  23. #include "ax25.h"
  24. #include "trace.h"
  25. #include <time.h>
  26.  
  27. struct EGTAB eagle[EGMAX];    /* Device table - one entry per card */
  28. void eg0vec(),write_scc(),rts(),waitmsec();
  29. void (*eghandle[])() = { eg0vec };  /* handler interrupt vector table */
  30. struct egchan egchan[2*EGMAX];       /* channel table - 2 entries per card */
  31. int16 egnbr;
  32.  
  33. /* Master interrupt handler.  One interrupt at a time is handled.
  34.  * here. Service routines are called from here.
  35.  */
  36. void
  37. egint(dev)
  38. int16 dev;
  39. {
  40.     register char st;
  41.     register int16 pcbase;
  42.     struct egchan *hp;
  43.     void egrxint(),egtxint(),egexint();
  44.  
  45.     eagle[dev].ints++;
  46.     pcbase = eagle[dev].addr;
  47.  
  48.     /* Read interrupt status register from channel A */
  49.     while((st = read_scc(pcbase+CHANA+CTL,R3)) != 0) {
  50.         /* Use IFs to process ALL interrupts pending
  51.          * because we need to check all interrupt conditions
  52.          */
  53.         if (st & CHARxIP) {
  54.             /* Channel A Rcv Interrupt Pending */
  55.             hp = &egchan[2 * dev];
  56.             egrxint(hp);
  57.         } else if (st & CHATxIP) {
  58.             /* Channel A Transmit Int Pending */
  59.             hp = &egchan[2 * dev];
  60.             egtxint(hp);
  61.         } else if (st & CHAEXT) {
  62.             /* Channel A External Status Int */
  63.             hp = &egchan[2 * dev];
  64.             egexint(hp);
  65.         } else if (st & CHBRxIP) {
  66.             /* Channel B Rcv Interrupt Pending */
  67.             hp = &egchan[(2 * dev)+1];
  68.             egrxint(hp);
  69.         } else if (st & CHBTxIP) {
  70.             /* Channel B Transmit Int Pending */
  71.             hp = &egchan[(2 * dev)+1];
  72.             egtxint(hp);
  73.         } else if (st & CHBEXT) {
  74.             /* Channel B External Status Int */
  75.             hp = &egchan[(2 * dev)+1];
  76.             egexint(hp);
  77.         }
  78.         /* Reset highest interrupt under service */
  79.         write_scc(hp->base+CTL,R0,RES_H_IUS);
  80.     } /* End of while loop on int processing */
  81. }
  82.  
  83. /* Eagle SIO External/Status interrupts
  84.  * This can be caused by a receiver abort, or a Tx UNDERRUN/EOM.
  85.  * Receiver automatically goes to Hunt on an abort.
  86.  *
  87.  * If the Tx Underrun interrupt hits, change state and
  88.  * issue a reset command for it, and return.
  89.  */
  90. static void
  91. egexint(hp)
  92. register struct egchan *hp;
  93. {
  94.     char st, i_state;
  95.  
  96.     i_state = disable();        /* disable interrupts */
  97.     hp->exints++;
  98.     st = read_scc(hp->base+CTL,R0);     /* Fetch status */
  99.  
  100.     /* Check for Tx UNDERRUN/EOM - only in Transmit Mode */
  101.     if((hp->rstate==0) && (st & TxEOM)) {
  102.         /* if in UNDERRUN, go to FLAGOUT state
  103.          * see explanation under egtxint()
  104.          * CRC & FLAG now going out, so
  105.          * wait for Tx BUffer Empty int
  106.          */
  107.  
  108.         /* If we are not in underrun, this is an unexpected
  109.          * underrun.  EOM bit should be set, so the SCC will
  110.          * now send an abort
  111.          */
  112.  
  113.         if(hp->tstate == UNDERRUN)
  114.             hp->tstate = FLAGOUT;
  115.  
  116.         /* Tx Buff EMPTY interrupt occurs after CRC is sent */
  117.     }
  118.  
  119.     /* Receive Mode only
  120.      * This triggers when hunt mode is entered, & since an ABORT
  121.      * automatically enters hunt mode, we use that to clean up
  122.      * any waiting garbage
  123.      */
  124.     if((hp->rstate == ACTIVE) && (st & BRK_ABRT)) {
  125.         hp->rcp = hp->rcvbuf->data;
  126.         hp->rcvbuf->cnt = 0;          /* rewind on DCD transition */
  127.         hp->aborts++;              /* nbr aborts * 2 */
  128.     }
  129.  
  130.     /* reset external status latch */
  131.     write_scc(CTL+hp->base,R0,RES_EXT_INT);
  132.  
  133.     restore(i_state);
  134. }
  135.  
  136. /* EG receive interrupt handler. The first receive buffer is pre-allocated
  137.  * in the init routine.  Thereafter, it is filled here, queued out, and a
  138.  * new one acquired.  CRC, OVERRUN and TOOBIG errors merely 'rewind' the
  139.  * pointers and reuse the same buffer.
  140.  */
  141. static void
  142. egrxint(hp)
  143. register struct egchan *hp;
  144. {
  145.     register int16 base;
  146.     char rse, i_state;
  147.  
  148.     i_state = disable();        /* disable interrupts */
  149.     hp->rxints++;
  150.     base = hp->base;
  151.  
  152.     if ((read_scc(base+CTL,R0)) & Rx_CH_AV) {
  153.         /* there is a char to be stored
  154.          * read special condition bits before reading the data char
  155.          */
  156.         rse = read_scc(hp->base+CTL,R1); /* get status byte from R1 */
  157.         if(rse & Rx_OVR) {
  158.             /* Rx overrun - toss buffer */
  159.             hp->rcp = hp->rcvbuf->data;    /* reset buffer pointers */
  160.             hp->rcvbuf->cnt = 0;
  161.             hp->rstate = RXERROR;    /* set error flag */
  162.             hp->rovers++;        /* count overruns */
  163.         } else if(hp->rcvbuf->cnt >= hp->bufsiz) {
  164.             /* Too large -- toss buffer */
  165.             hp->toobig++;
  166.             hp->rcp = hp->rcvbuf->data;    /* reset buffer pointers */
  167.             hp->rcvbuf->cnt = 0;
  168.             hp->rstate = TOOBIG;    /* when set, chars are not stored */
  169.         }
  170.         /* ok, we can store the received character now */
  171.         if(hp->rstate == ACTIVE) {        /* If no errors... */
  172.             *hp->rcp++ = inportb(base+DATA);    /* char to rcv buff */
  173.             hp->rcvbuf->cnt++;            /* bump count */
  174.         } else {
  175.             /* got to empty FIFO */
  176.             (void) inportb(base+DATA);
  177.             write_scc(hp->base+CTL,R0,ERR_RES);    /* reset err latch */
  178.             hp->rstate = ACTIVE;
  179.         }
  180.     }
  181.     /* char has been stored
  182.      * read special condition bits
  183.      */
  184.     rse = read_scc(hp->base+CTL,R1);     /* get status byte from R1 */
  185.  
  186.     /* The End of Frame bit is ALWAYS associated with a character,
  187.      * usually, it is the last CRC char.  Only when EOF is true can
  188.      * we look at the CRC byte to see if we have a valid frame
  189.      */
  190.     if(rse & END_FR) {
  191.         hp->rxframes++;
  192.         /* END OF FRAME -- Make sure Rx was active */
  193.         if(hp->rcvbuf->cnt > 0) {        /* any data to store */
  194.             /* looks like a frame was received
  195.              * now is the only time we can check for CRC error
  196.              */
  197.             if((rse & CRC_ERR) || (hp->rstate > ACTIVE) || (hp->rcvbuf->cnt < 10)) {
  198.                 /* error occurred; toss frame */
  199.                 if(rse & CRC_ERR)
  200.                     hp->crcerr++;    /* count CRC errs */
  201.                 if(hp->rstate == RXERROR)
  202.                     hp->rovers++;
  203.                 /* don't throw away buffer -
  204.                  * merely reset the pointers
  205.                  */
  206.                 hp->rcp = hp->rcvbuf->data;
  207.                 hp->rcvbuf->cnt = 0;
  208.             } else {
  209.                 /* Here we have a valid frame */
  210.                 hp->rcvbuf->cnt -= 2;           /* Toss 2 crc bytes */
  211.                 enqueue(&hp->rcvq,hp->rcvbuf);       /* queue it in */
  212.                 hp->enqueued++;
  213.  
  214.                 /* packet queued - get buffer for next frame */
  215.                 hp->rcvbuf = alloc_mbuf(hp->bufsiz);
  216.                 hp->rcp = hp->rcvbuf->data;
  217.                 hp->rcvbuf->cnt = 0;
  218.                 if(hp->rcvbuf == NULLBUF) {
  219.                     /* No memory, abort receiver */
  220.                     restore(i_state);
  221.                     printf("DISASTER! Out of Memory for Receive!\n");
  222.                     fflush(stdout);
  223.                     write_scc(CTL+base,R3,Rx8);
  224.                     return;
  225.                 }
  226.             } /* end good frame queued */
  227.         }  /* end check for active receive upon EOF */
  228.         hp->rstate = ACTIVE;    /* and clear error status */
  229.     } /* end EOF check */
  230.     restore(i_state);
  231. }
  232.  
  233. /* egchan transmit interrupt service routine
  234.  *
  235.  * The state variable tstate, along with some static pointers,
  236.  * represents the state of the transmit "process".
  237.  */
  238. static void
  239. egtxint(hp)
  240. register struct egchan *hp;
  241. {
  242.     register int16 base;
  243.     char i_state,c;
  244.  
  245.     i_state = disable();
  246.  
  247.     if(hp->tstate != DEFER && hp->tstate) hp->txints++;
  248.     base = hp->base;
  249.  
  250.     switch(hp->tstate) {
  251.     case FLAGOUT:
  252.         /* Here after CRC sent and Tx interrupt fires.
  253.          * To give the SCC a chance to get the FLAG
  254.          * out, we delay 100 Ms
  255.          */
  256.         hp->tstate = IDLE;    /* fall thru to IDLE */
  257.         waitmsec(10);        /* 100 msec wait for flag Tx */
  258.         /* Note, it may be possible to stuff out a
  259.          * meaningless character, wait for the interrupt
  260.          * then go to idle.  A delay is absolutely necessary
  261.          * here else the packet gets truncated prematurely
  262.          * when no other packet is waiting to be sent.
  263.          * IDLE state indicates either we are starting a brand new packet
  264.          * as a result of its being queued for transmission (egtxint called
  265.          * from eg_raw), or after a frame has been transmitted (as a
  266.          * result of a Tx buffer empty interrupt after the CRC/FLAG
  267.          */
  268.     case IDLE:
  269.         /* Transmitter idle. Find a frame for t